package com.eva.job;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.eva.dao.system.SystemJobMapper;
import com.eva.dao.system.model.SystemJob;
import com.eva.job.constants.JobConstants;
import com.eva.service.system.SystemJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Component
public class JobInitializer implements ApplicationRunner {

    @Resource
    private SystemJobService systemJobService;

    @Resource
    private SystemJobMapper systemJobMapper;

    @Resource
    private SchedulerProxy schedulerProxy;

    @Override
    public void run (ApplicationArguments args) {
        log.debug("初始化定时任务");
        // 修复JOB
        this.repairJobs();
        // 初始化JOB
        long startTime = System.currentTimeMillis();
        SystemJob queryJobDto = new SystemJob();
        queryJobDto.setStatus(JobConstants.JobStatus.READY.getCode());
        queryJobDto.setDisabled(Boolean.FALSE);
        List<SystemJob> jobs = systemJobService.findList(queryJobDto);
        for (SystemJob job : jobs) {
            schedulerProxy.createAndScheduleCronJob(SchedulerProxy.CronJob.builder()
                    .id(job.getId())
                    .handler(job.getHandler())
                    .cronExpression(job.getCronExpression())
                    .disallowConcurrent(job.getDisallowConcurrent())
                    .build());
            log.debug("定时任务 '{}' 初始化完毕。", job.getJobName());
        }
        log.debug("定时任务初始化完成，耗时 {} 毫秒", System.currentTimeMillis() - startTime);
    }

    /**
     * 修复Jobs，防止因服务器宕机导致正在执行中的Job状态未得到处理，导致任务丢失
     */
    private void repairJobs () {
        log.debug("重置定时任务信息");
        // 将运行中的JOB调整为准备状态 & 将预计下一次执行时间调整为null
        systemJobMapper.update(null, new LambdaUpdateWrapper<SystemJob>()
                .set(SystemJob::getStatus, JobConstants.JobStatus.READY.getCode())
                .set(SystemJob::getNextFireTime, null)
                .eq(SystemJob::getStatus, JobConstants.JobStatus.RUNNING.getCode())
                .eq(SystemJob::getDeleted, Boolean.FALSE)
        );
        log.debug("重置定时任务片段信息");
    }
}
